package com.tools.web.interceptor.limit;

import com.tools.common.object.Note;
import com.tools.common.thread.Timeunit;
import com.tools.middle.redis.client.JedisClusterPlus;
import com.tools.web.interceptor.auth.AuthenticationManager;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * 使用 JedisClusterPlus 客户端操作 Redis 集群实现的 IP-URI 同 IP 请求同一个接口的请求限流拦截器
 * */
@Note("使用 JedisClusterPlus 客户端操作 Redis 集群实现的 IP-URI 同 IP 请求同一个接口的请求限流拦截器")
public final class JedisClusterPlusRequestLimitInterceptor extends AbsRequestLimitInterceptor implements RequestLimitRedisLuaScript {

    @Note("操作 Redis 集群的客户端")
    private final JedisClusterPlus jedisClusterPlus;

    public JedisClusterPlusRequestLimitInterceptor(JedisClusterPlus jedisClusterPlus, RequestLimitSource source) {
        this(jedisClusterPlus, source, null);
    }

    public JedisClusterPlusRequestLimitInterceptor(JedisClusterPlus jedisClusterPlus, RequestLimitSource source, AuthenticationManager authenticationManager) {
        super(source, authenticationManager);
        this.jedisClusterPlus = Objects.requireNonNull(jedisClusterPlus, "操作 Redis 集群的客户端 JedisClusterPlus 不能为 null");
    }


    @Override
    protected boolean protected_checkIsAllow(RequestLimit limit, HttpServletRequest request, HttpServletResponse response,
                                             AuthenticationManager authenticationManager) throws Exception {
        String key = super.protected_getKey(request);
        long time = limit.time();
        Timeunit timeunit = limit.timeunit();
        long expiration = Timeunit.toSecond(time, timeunit);
        Long result = (Long) this.jedisClusterPlus.eval(CHECK_LIMIT, 1, key, expiration, limit.allow());
        if(result != null && result == 1) return true;
        response.getWriter().write(super.getLimitErrorMessage());
        if(authenticationManager != null) {
            authenticationManager.handleDisable(request);
        }
        return false;
    }
}
